#include "eeprom.h"

/*Declare SFR associated with the IAP */
#ifdef __SDCC
sfr at 0xE2 IAP_DATA; //Flash data register
sfr at 0xE3 IAP_ADDRH; //Flash address HIGH 
sfr at 0xE4 IAP_ADDRL ; //Flash address LOW
sfr at 0xE5 IAP_CMD; //Flash command register
sfr at 0xE6 IAP_TRIG; //Flash command trigger 
sfr at 0xE7 IAP_CONTR; //Flash control register
#else //Keil C51
sfr IAP_DATA = 0xE2; //Flash data register M 
sfr IAP_ADDRH = 0xE3; //Flash address HIGH 
sfr IAP_ADDRL = 0xE4; //Flash address LOW
sfr IAP_CMD = 0xE5; //Flash command register
sfr IAP_TRIG = 0xE6; //Flash command trigger 
sfr IAP_CONTR = 0xE7; //Flash control register
#endif

/*Define ISP/IAP/EEPROM command*/ 
#define CMD_IDLE 0 //Stand-By 
#define CMD_READ 1 //Byte-Read 
#define CMD_PROGRAM 2 //Byte-Program 
#define CMD_ERASE 3 //Sector-Erase

/*Define ISP/IAP/EEPROM operation const for IAP_CONTR*/
// #define ENABLE_IAP 0x80 //if SYSCLK<40MHz 
#define ENABLE_IAP 0x81 //if SYSCLK<20MHz
// #define ENABLE_IAP 0x82 //if SYSCLK<10MHz
// #define ENABLE_IAP 0x83 //if SYSCLK<5MHz


/*---------------------------- 
Disable ISP/IAP/EEPROM function Make MCU in a safe state
----------------------------*/
void IapIdle()
{
    IAP_CONTR = 0; //Close IAP function 
    IAP_CMD = 0; //Clear command to standby 
    IAP_TRIG = 0; //Clear trigger register 
    IAP_ADDRH = 0x80; //Data ptr point to non-EEPROM area 
    IAP_ADDRL = 0; //Clear IAP address to prevent misuse 
}

/*----------------------------
Read one byte from ISP/IAP/EEPROM area
Input: addr (ISP/IAP/EEPROM address) 
Output:Flash data 
----------------------------*/
BYTE IapReadByte(WORD addr)
{ 
    BYTE dat; //Data buffer 

    IAP_CONTR = ENABLE_IAP; //Open IAP function, and set wait time
    IAP_CMD = CMD_READ; //Set ISP/IAP/EEPROM READ command
    IAP_ADDRL = addr; //Set ISP/IAP/EEPROM address low
    IAP_ADDRH = addr >> 8; //Set ISP/IAP/EEPROM address high 
    IAP_TRIG = 0x46; //Send trigger command1 (0x46) 
    IAP_TRIG = 0xb9; //Send trigger command2 (0xb9) 
    _nop_(); //MCU will hold here until ISP/IAP/EEPROM operation complete 
    dat = IAP_DATA; //Read ISP/IAP/EEPROM data 
    IapIdle(); //Close ISP/IAP/EEPROM function 

    return dat; //Return Flash data
}

/*----------------------------
Program one byte to ISP/IAP/EEPROM area
Input: addr (ISP/IAP/EEPROM address) 
       dat (ISP/IAP/EEPROM data)
Output:- 
----------------------------*/
void IapProgramByte(WORD addr, BYTE dat) 
{ 
    IAP_CONTR = ENABLE_IAP; //Open IAP function, and set wait time 
    IAP_CMD = CMD_PROGRAM; //Set ISP/IAP/EEPROM PROGRAM command 
    IAP_ADDRL = addr; //Set ISP/IAP/EEPROM address low 
    IAP_ADDRH = addr >> 8; //Set ISP/IAP/EEPROM address high 
    IAP_DATA = dat; //Write ISP/IAP/EEPROM data 
    IAP_TRIG = 0x46; //Send trigger command1 (0x46) 
    IAP_TRIG = 0xb9; //Send trigger command2 (0xb9) 
    _nop_(); //MCU will hold here until ISP/IAP/EEPROM operation complete 
    IapIdle(); 
}

/*----------------------------
Erase one sector area
Input: addr (ISP/IAP/EEPROM address)
Output:-
----------------------------*/ 
void IapEraseSector(WORD addr) 
{
    IAP_CONTR = ENABLE_IAP; //Open IAP function, and set wait time
    IAP_CMD = CMD_ERASE; //Set ISP/IAP/EEPROM ERASE command 
    IAP_ADDRL = addr; //Set ISP/IAP/EEPROM address low 
    IAP_ADDRH = addr >> 8; //Set ISP/IAP/EEPROM address high 
    IAP_TRIG = 0x46; //Send trigger command1 (0x46) 
    IAP_TRIG = 0xb9;  //Send trigger command2 (0xb9) 
    _nop_();       //MCU will hold here until ISP/IAP/EEPROM operation complete 
    IapIdle(); 
}
